import logging
import base64
import time
from patch_tracking.util.gitee_api import post_create_branch, post_upload_patch, post_create_issue, \
    post_create_pull_request, get_path_content, put_upload_spec
from patch_tracking.util.github_api import GitHubApi
from patch_tracking.database.models import Tracking
from patch_tracking.api.business import update_tracking, create_issue
from patch_tracking.task import scheduler
from patch_tracking.util.spec import Spec

logger = logging.getLogger(__name__)


def get_track_from_db():
    all_track = Tracking.query.filter_by(enabled=True)
    return all_track


def single_upload_patch_to_gitee(track):
    cur_time = time.strftime("%Y%m%d%H%M%S", time.localtime())
    with scheduler.app.app_context():
        patch = single_get_scm_patch(track)
        if patch:
            issue = single_upload_patch(patch, cur_time)
            single_create_issue_db(issue)


def get_all_commit_info(scm_repo, db_commit, latest_commit):
    commit_lst = list()
    github_api = GitHubApi()

    while db_commit != latest_commit:
        status, result = github_api.get_commit_info(scm_repo, latest_commit)
        logger.debug('get_commit_info: %s %s', status, result)
        if status == 'success':
            if 'parent' in result:
                ret = github_api.get_patch(scm_repo, latest_commit, latest_commit)
                logger.debug('get patch api ret: %s', ret)
                if ret['status'] == 'success':
                    result['patch_content'] = ret['api_ret']
                    # 反序插入
                    commit_lst.insert(0, result)
                else:
                    logger.error('Get scm: %s commit: %s patch failed. Result: %s', scm_repo, latest_commit, result)

                latest_commit = result['parent']
            else:
                logger.info('Successful get scm commit from %s to %s ID/message/time/patch.', db_commit, latest_commit)
                break
        else:
            logger.error('Get scm: %s commit: %s ID/message/time failed. Result: %s', scm_repo, latest_commit, result)

    return commit_lst


def single_get_scm_patch(track):
    '''
    遍历Tracking数据表, 获取enabled仓的patch文件，不同的仓有不同的获取方式
    :return:
    '''
    scm_dict = dict()
    github_api = GitHubApi()
    if track.enabled is True:
        scm_dict['scm_repo'] = track.scm_repo
        scm_dict['scm_branch'] = track.scm_branch
        scm_dict['scm_commit'] = Tracking.query.filter_by(repo=track.repo, branch=track.branch).first().scm_commit
        scm_dict['enabled'] = track.enabled
        scm_dict['repo'] = track.repo
        scm_dict['branch'] = track.branch

    status, result = github_api.get_latest_commit(scm_dict['scm_repo'], scm_dict['scm_branch'])
    logger.debug('get_latest_commit: %s %s', status, result)

    if status == 'success':
        commit_id = result['latest_commit']
        if not scm_dict['scm_commit']:
            data = {
                'repo': scm_dict['repo'],
                'branch': scm_dict['branch'],
                'enabled': scm_dict['enabled'],
                'scm_commit': commit_id,
                'scm_branch': scm_dict['scm_branch'],
                'scm_repo': scm_dict['scm_repo']
            }
            update_tracking(data)
        else:
            if commit_id != scm_dict['scm_commit']:
                commit_lst = get_all_commit_info(scm_dict['scm_repo'], scm_dict['scm_commit'], commit_id)
                scm_dict['commit_lst'] = commit_lst
                return scm_dict
            logger.info(
                'Latest commit id not change of scm_repo: %s scm_branch: %s. Nothing need to do.', scm_dict['scm_repo'],
                scm_dict['scm_branch']
            )
    else:
        logger.error(
            'Fail to get latest commit id of scm_repo: %s scm_branch: %s. Return val: %s', scm_dict['scm_repo'],
            scm_dict['scm_branch'], result
        )
    return None


# pylint: disable=R0914, R0915, R1710
def single_upload_patch(patch, cur_time):
    '''
    创建临时分支，提交文件，创建PR和issue
    :return:
    '''
    issue_dict = dict()
    if patch:
        repo = patch['repo']
        branch = patch['branch']
        issue_dict['repo'] = repo
        issue_dict['branch'] = branch
        new_branch = 'patch-tracking/' + cur_time
        result = post_create_branch(repo, branch, new_branch)
        if result == 'success':
            logger.info('Successful create branch: %s', new_branch)
        else:
            logger.error('Fail to create branch: %s', new_branch)
        issue_body_lst = list()
        patch_lst = list()
        # 表格格式会导致 Gitee 敏感词，先去掉
        issue_table = ""
        for latest_commit in patch['commit_lst']:
            scm_commit_url = '/'.join(['https://github.com', patch['scm_repo'], 'commit', latest_commit['commit_id']])
            issue_table += '[{}]({}) | {} | {}'.format(
                latest_commit['commit_id'][0:7], scm_commit_url, latest_commit['time'], latest_commit['message']
            ) + '\n'
            patch_file_content = latest_commit['patch_content']
            result = post_upload_patch(
                repo, new_branch, latest_commit['commit_id'], str(patch_file_content), cur_time, scm_commit_url
            )
            if result == 'success':
                logger.info('Successfully upload patch file of commit: %s', latest_commit['commit_id'])
            else:
                logger.error('Fail to upload patch file of commit: %s', latest_commit['commit_id'])
            patch_lst.append(str(latest_commit['commit_id']))

        issue_body = issue_table

        logger.debug(issue_body)
        result = post_create_issue(repo, issue_body, cur_time)
        if result[0] == 'success':
            issue_num = result[1]
            logger.info('Successfully create issue: %s', issue_body_lst)
            ret = post_create_pull_request(repo, branch, new_branch, issue_num, cur_time)
            if ret == 'success':
                logger.info('Successfully create PR of issue: %s.', issue_num)
            else:
                logger.error('Fail to create PR of issue: %s. Result: %s', issue_num, ret)
            issue_dict['issue'] = issue_num

            spec_file = repo + '.spec'

            patch_file_lst = [patch + '.patch' for patch in patch_lst]

            log_title = "{} patch-tracking".format(cur_time)
            log_content = "append patch file of upstream'' repository from <{}> to <{}>".format(
                patch_lst[0], patch_lst[-1]
            )

            ret = get_path_content(repo, branch, spec_file)
            spec_content = str(base64.b64decode(ret['content']), encoding='utf-8')
            spec_sha = ret['sha']
            new_spec = modify_spec(log_title, log_content, patch_file_lst, spec_content)
            update_spec(repo, new_branch, cur_time, new_spec, spec_sha)

            data = {
                'repo': patch['repo'],
                'branch': patch['branch'],
                'enabled': patch['enabled'],
                'scm_commit': patch['commit_lst'][0]['commit_id'],
                'scm_branch': patch['scm_branch'],
                'scm_repo': patch['scm_repo']
            }
            update_tracking(data)
        else:
            logger.error('Fail to create issue: %s. Result: %s', issue_body_lst, result[1])

        return issue_dict


def modify_spec(log_title, log_content, patch_file_lst, spec_content):
    spec = Spec(spec_content)
    return spec.update(log_title, log_content, patch_file_lst)


def update_spec(repo, branch, cur_time, spec_content, spec_sha):
    ret = put_upload_spec(repo, branch, cur_time, spec_content, spec_sha)
    if ret == 'success':
        logger.info('Successfully update spec file.')
    else:
        logger.error('Fail to update spec file. Result: %s', 1)


def single_create_issue_db(issue):
    if issue:
        issue_num = issue['issue']
        tracking = Tracking.query.filter_by(repo=issue['repo'], branch=issue['branch']).first()
        tracking_repo = tracking.repo
        tracking_branch = tracking.branch
        data = {'issue': issue_num, 'repo': tracking_repo, 'branch': tracking_branch}
        logger.debug('issue data: %s', data)
        create_issue(data)
